// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/*
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;

#endregion

#nullable enable

namespace AM.Reporting.Barcode.QRCode
{
    /*/// <summary> See ISO 18004:2006 Annex D
    ///
    /// </summary>
    /// <author>  Sean Owen
    /// </author>
    /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
    /// </author>*/
    internal sealed class Version
    {
        public int VersionNumber { get; }

        public int[] AlignmentPatternCenters { get; }

        public int TotalCodewords { get; }

        public int DimensionForVersion => 17 + 4 * VersionNumber;

        //UPGRADE_NOTE: Final was removed from the declaration of 'VERSIONS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        private static readonly Version[] VERSIONS = buildVersions();

        //UPGRADE_NOTE: Final was removed from the declaration of 'versionNumber '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"

        //UPGRADE_NOTE: Final was removed from the declaration of 'alignmentPatternCenters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"

        //UPGRADE_NOTE: Final was removed from the declaration of 'ecBlocks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        private ECBlocks[] ecBlocks;

        //UPGRADE_NOTE: Final was removed from the declaration of 'totalCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"

        private Version (int versionNumber, int[] alignmentPatternCenters, ECBlocks ecBlocks1, ECBlocks ecBlocks2,
            ECBlocks ecBlocks3, ECBlocks ecBlocks4)
        {
            this.VersionNumber = versionNumber;
            this.AlignmentPatternCenters = alignmentPatternCenters;
            ecBlocks = new ECBlocks[] { ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4 };
            var total = 0;
            var ecCodewords = ecBlocks1.ECCodewordsPerBlock;
            ECB[] ecbArray = ecBlocks1.getECBlocks();
            for (var i = 0; i < ecbArray.Length; i++)
            {
                var ecBlock = ecbArray[i];
                total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
            }

            TotalCodewords = total;
        }

        public ECBlocks getECBlocksForLevel (ErrorCorrectionLevel ecLevel)
        {
            return ecBlocks[ecLevel.ordinal()];
        }

        public static Version getVersionForNumber (int versionNumber)
        {
            if (versionNumber is < 1 or > 40)
            {
                throw new ArgumentException();
            }

            return VERSIONS[versionNumber - 1];
        }

        /*/// <summary> <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
        /// use blocks of differing sizes within one version, so, this encapsulates the parameters for
        /// each set of blocks. It also holds the number of error-correction codewords per block since it
        /// will be the same across all blocks within one version.</p>
        /// </summary>*/
        public sealed class ECBlocks
        {
            public int ECCodewordsPerBlock { get; }

            public int NumBlocks
            {
                get
                {
                    var total = 0;
                    for (var i = 0; i < ecBlocks.Length; i++)
                    {
                        total += ecBlocks[i].Count;
                    }

                    return total;
                }
            }

            public int TotalECCodewords => ECCodewordsPerBlock * NumBlocks;

            //UPGRADE_NOTE: Final was removed from the declaration of 'ecCodewordsPerBlock '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"

            //UPGRADE_NOTE: Final was removed from the declaration of 'ecBlocks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
            private ECB[] ecBlocks;

            internal ECBlocks (int ecCodewordsPerBlock, ECB ecBlocks)
            {
                this.ECCodewordsPerBlock = ecCodewordsPerBlock;
                this.ecBlocks = new ECB[] { ecBlocks };
            }

            internal ECBlocks (int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2)
            {
                this.ECCodewordsPerBlock = ecCodewordsPerBlock;
                ecBlocks = new ECB[] { ecBlocks1, ecBlocks2 };
            }

            public ECB[] getECBlocks()
            {
                return ecBlocks;
            }
        }

        /*/// <summary> <p>Encapsualtes the parameters for one error-correction block in one symbol version.
        /// This includes the number of data codewords, and the number of times a block with these
        /// parameters is used consecutively in the QR code version's format.</p>
        /// </summary>*/
        public sealed class ECB
        {
            public int Count { get; }

            public int DataCodewords { get; }

            //UPGRADE_NOTE: Final was removed from the declaration of 'count '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"

            //UPGRADE_NOTE: Final was removed from the declaration of 'dataCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"

            internal ECB (int count, int dataCodewords)
            {
                this.Count = count;
                this.DataCodewords = dataCodewords;
            }
        }

        // <summary> See ISO 18004:2006 6.5.1 Table 9</summary>
        private static Version[] buildVersions()
        {
            return new Version[]
            {
                new Version (1, new int[] { }, new ECBlocks (7, new ECB (1, 19)), new ECBlocks (10, new ECB (1, 16)),
                    new ECBlocks (13, new ECB (1, 13)), new ECBlocks (17, new ECB (1, 9))),
                new Version (2, new int[] { 6, 18 }, new ECBlocks (10, new ECB (1, 34)),
                    new ECBlocks (16, new ECB (1, 28)), new ECBlocks (22, new ECB (1, 22)),
                    new ECBlocks (28, new ECB (1, 16))),
                new Version (3, new int[] { 6, 22 }, new ECBlocks (15, new ECB (1, 55)),
                    new ECBlocks (26, new ECB (1, 44)), new ECBlocks (18, new ECB (2, 17)),
                    new ECBlocks (22, new ECB (2, 13))),
                new Version (4, new int[] { 6, 26 }, new ECBlocks (20, new ECB (1, 80)),
                    new ECBlocks (18, new ECB (2, 32)), new ECBlocks (26, new ECB (2, 24)),
                    new ECBlocks (16, new ECB (4, 9))),
                new Version (5, new int[] { 6, 30 }, new ECBlocks (26, new ECB (1, 108)),
                    new ECBlocks (24, new ECB (2, 43)), new ECBlocks (18, new ECB (2, 15), new ECB (2, 16)),
                    new ECBlocks (22, new ECB (2, 11), new ECB (2, 12))),
                new Version (6, new int[] { 6, 34 }, new ECBlocks (18, new ECB (2, 68)),
                    new ECBlocks (16, new ECB (4, 27)), new ECBlocks (24, new ECB (4, 19)),
                    new ECBlocks (28, new ECB (4, 15))),
                new Version (7, new int[] { 6, 22, 38 }, new ECBlocks (20, new ECB (2, 78)),
                    new ECBlocks (18, new ECB (4, 31)), new ECBlocks (18, new ECB (2, 14), new ECB (4, 15)),
                    new ECBlocks (26, new ECB (4, 13), new ECB (1, 14))),
                new Version (8, new int[] { 6, 24, 42 }, new ECBlocks (24, new ECB (2, 97)),
                    new ECBlocks (22, new ECB (2, 38), new ECB (2, 39)),
                    new ECBlocks (22, new ECB (4, 18), new ECB (2, 19)),
                    new ECBlocks (26, new ECB (4, 14), new ECB (2, 15))),
                new Version (9, new int[] { 6, 26, 46 }, new ECBlocks (30, new ECB (2, 116)),
                    new ECBlocks (22, new ECB (3, 36), new ECB (2, 37)),
                    new ECBlocks (20, new ECB (4, 16), new ECB (4, 17)),
                    new ECBlocks (24, new ECB (4, 12), new ECB (4, 13))),
                new Version (10, new int[] { 6, 28, 50 }, new ECBlocks (18, new ECB (2, 68), new ECB (2, 69)),
                    new ECBlocks (26, new ECB (4, 43), new ECB (1, 44)),
                    new ECBlocks (24, new ECB (6, 19), new ECB (2, 20)),
                    new ECBlocks (28, new ECB (6, 15), new ECB (2, 16))),
                new Version (11, new int[] { 6, 30, 54 }, new ECBlocks (20, new ECB (4, 81)),
                    new ECBlocks (30, new ECB (1, 50), new ECB (4, 51)),
                    new ECBlocks (28, new ECB (4, 22), new ECB (4, 23)),
                    new ECBlocks (24, new ECB (3, 12), new ECB (8, 13))),
                new Version (12, new int[] { 6, 32, 58 }, new ECBlocks (24, new ECB (2, 92), new ECB (2, 93)),
                    new ECBlocks (22, new ECB (6, 36), new ECB (2, 37)),
                    new ECBlocks (26, new ECB (4, 20), new ECB (6, 21)),
                    new ECBlocks (28, new ECB (7, 14), new ECB (4, 15))),
                new Version (13, new int[] { 6, 34, 62 }, new ECBlocks (26, new ECB (4, 107)),
                    new ECBlocks (22, new ECB (8, 37), new ECB (1, 38)),
                    new ECBlocks (24, new ECB (8, 20), new ECB (4, 21)),
                    new ECBlocks (22, new ECB (12, 11), new ECB (4, 12))),
                new Version (14, new int[] { 6, 26, 46, 66 }, new ECBlocks (30, new ECB (3, 115), new ECB (1, 116)),
                    new ECBlocks (24, new ECB (4, 40), new ECB (5, 41)),
                    new ECBlocks (20, new ECB (11, 16), new ECB (5, 17)),
                    new ECBlocks (24, new ECB (11, 12), new ECB (5, 13))),
                new Version (15, new int[] { 6, 26, 48, 70 }, new ECBlocks (22, new ECB (5, 87), new ECB (1, 88)),
                    new ECBlocks (24, new ECB (5, 41), new ECB (5, 42)),
                    new ECBlocks (30, new ECB (5, 24), new ECB (7, 25)),
                    new ECBlocks (24, new ECB (11, 12), new ECB (7, 13))),
                new Version (16, new int[] { 6, 26, 50, 74 }, new ECBlocks (24, new ECB (5, 98), new ECB (1, 99)),
                    new ECBlocks (28, new ECB (7, 45), new ECB (3, 46)),
                    new ECBlocks (24, new ECB (15, 19), new ECB (2, 20)),
                    new ECBlocks (30, new ECB (3, 15), new ECB (13, 16))),
                new Version (17, new int[] { 6, 30, 54, 78 }, new ECBlocks (28, new ECB (1, 107), new ECB (5, 108)),
                    new ECBlocks (28, new ECB (10, 46), new ECB (1, 47)),
                    new ECBlocks (28, new ECB (1, 22), new ECB (15, 23)),
                    new ECBlocks (28, new ECB (2, 14), new ECB (17, 15))),
                new Version (18, new int[] { 6, 30, 56, 82 }, new ECBlocks (30, new ECB (5, 120), new ECB (1, 121)),
                    new ECBlocks (26, new ECB (9, 43), new ECB (4, 44)),
                    new ECBlocks (28, new ECB (17, 22), new ECB (1, 23)),
                    new ECBlocks (28, new ECB (2, 14), new ECB (19, 15))),
                new Version (19, new int[] { 6, 30, 58, 86 },
                    new ECBlocks (28, new ECB (3, 113), new ECB (4, 114)),
                    new ECBlocks (26, new ECB (3, 44), new ECB (11, 45)), new ECBlocks (26, new ECB (17, 21),
                        new ECB (4, 22)), new ECBlocks (26, new ECB (9, 13), new ECB (16, 14))),
                new Version (20, new int[] { 6, 34, 62, 90 }, new ECBlocks (28, new ECB (3, 107), new ECB (5, 108)),
                    new ECBlocks (26, new ECB (3, 41), new ECB (13, 42)),
                    new ECBlocks (30, new ECB (15, 24), new ECB (5, 25)),
                    new ECBlocks (28, new ECB (15, 15), new ECB (10, 16))),
                new Version (21, new int[] { 6, 28, 50, 72, 94 }, new ECBlocks (28, new ECB (4, 116), new ECB (4, 117)),
                    new ECBlocks (26, new ECB (17, 42)), new ECBlocks (28, new ECB (17, 22), new ECB (6, 23)),
                    new ECBlocks (30, new ECB (19, 16), new ECB (6, 17))),
                new Version (22, new int[] { 6, 26, 50, 74, 98 }, new ECBlocks (28, new ECB (2, 111), new ECB (7, 112)),
                    new ECBlocks (28, new ECB (17, 46)), new ECBlocks (30, new ECB (7, 24), new ECB (16, 25)),
                    new ECBlocks (24, new ECB (34, 13))),
                new Version (23, new int[] { 6, 30, 54, 74, 102 },
                    new ECBlocks (30, new ECB (4, 121), new ECB (5, 122)),
                    new ECBlocks (28, new ECB (4, 47), new ECB (14, 48)),
                    new ECBlocks (30, new ECB (11, 24), new ECB (14, 25)),
                    new ECBlocks (30, new ECB (16, 15), new ECB (14, 16))),
                new Version (24, new int[] { 6, 28, 54, 80, 106 },
                    new ECBlocks (30, new ECB (6, 117), new ECB (4, 118)),
                    new ECBlocks (28, new ECB (6, 45), new ECB (14, 46)),
                    new ECBlocks (30, new ECB (11, 24), new ECB (16, 25)),
                    new ECBlocks (30, new ECB (30, 16), new ECB (2, 17))),
                new Version (25, new int[] { 6, 32, 58, 84, 110 },
                    new ECBlocks (26, new ECB (8, 106), new ECB (4, 107)),
                    new ECBlocks (28, new ECB (8, 47), new ECB (13, 48)),
                    new ECBlocks (30, new ECB (7, 24), new ECB (22, 25)),
                    new ECBlocks (30, new ECB (22, 15), new ECB (13, 16))),
                new Version (26, new int[] { 6, 30, 58, 86, 114 },
                    new ECBlocks (28, new ECB (10, 114), new ECB (2, 115)),
                    new ECBlocks (28, new ECB (19, 46), new ECB (4, 47)),
                    new ECBlocks (28, new ECB (28, 22), new ECB (6, 23)),
                    new ECBlocks (30, new ECB (33, 16), new ECB (4, 17))),
                new Version (27,
                    new int[] { 6, 34, 62, 90, 118 }, new ECBlocks (30, new ECB (8, 122), new ECB (4, 123)),
                    new ECBlocks (28, new ECB (22, 45), new ECB (3, 46)),
                    new ECBlocks (30, new ECB (8, 23), new ECB (26, 24)), new ECBlocks (30, new ECB (12, 15),
                        new ECB (28, 16))),
                new Version (28, new int[] { 6, 26, 50, 74, 98, 122 },
                    new ECBlocks (30, new ECB (3, 117), new ECB (10, 118)),
                    new ECBlocks (28, new ECB (3, 45), new ECB (23, 46)),
                    new ECBlocks (30, new ECB (4, 24), new ECB (31, 25)),
                    new ECBlocks (30, new ECB (11, 15), new ECB (31, 16))),
                new Version (29, new int[] { 6, 30, 54, 78, 102, 126 },
                    new ECBlocks (30, new ECB (7, 116), new ECB (7, 117)),
                    new ECBlocks (28, new ECB (21, 45), new ECB (7, 46)),
                    new ECBlocks (30, new ECB (1, 23), new ECB (37, 24)),
                    new ECBlocks (30, new ECB (19, 15), new ECB (26, 16))),
                new Version (30, new int[] { 6, 26, 52, 78, 104, 130 },
                    new ECBlocks (30, new ECB (5, 115), new ECB (10, 116)),
                    new ECBlocks (28, new ECB (19, 47), new ECB (10, 48)),
                    new ECBlocks (30, new ECB (15, 24), new ECB (25, 25)),
                    new ECBlocks (30, new ECB (23, 15), new ECB (25, 16))),
                new Version (31, new int[] { 6, 30, 56, 82, 108, 134 },
                    new ECBlocks (30, new ECB (13, 115), new ECB (3, 116)),
                    new ECBlocks (28, new ECB (2, 46), new ECB (29, 47)),
                    new ECBlocks (30, new ECB (42, 24), new ECB (1, 25)),
                    new ECBlocks (30, new ECB (23, 15), new ECB (28, 16))),
                new Version (32, new int[] { 6, 34, 60, 86, 112, 138 }, new ECBlocks (30, new ECB (17, 115)),
                    new ECBlocks (28, new ECB (10, 46), new ECB (23, 47)),
                    new ECBlocks (30, new ECB (10, 24), new ECB (35, 25)),
                    new ECBlocks (30, new ECB (19, 15), new ECB (35, 16))),
                new Version (33, new int[] { 6, 30, 58, 86, 114, 142 },
                    new ECBlocks (30, new ECB (17, 115), new ECB (1, 116)),
                    new ECBlocks (28, new ECB (14, 46), new ECB (21, 47)),
                    new ECBlocks (30, new ECB (29, 24), new ECB (19, 25)),
                    new ECBlocks (30, new ECB (11, 15), new ECB (46, 16))),
                new Version (34, new int[] { 6, 34, 62, 90, 118, 146 },
                    new ECBlocks (30, new ECB (13, 115), new ECB (6, 116)),
                    new ECBlocks (28, new ECB (14, 46), new ECB (23, 47)),
                    new ECBlocks (30, new ECB (44, 24), new ECB (7, 25)),
                    new ECBlocks (30, new ECB (59, 16), new ECB (1, 17))),
                new Version (35,
                    new int[] { 6, 30, 54, 78, 102, 126, 150 }, new ECBlocks (30, new ECB (12, 121), new ECB (7, 122)),
                    new ECBlocks (28, new ECB (12, 47), new ECB (26, 48)), new ECBlocks (30, new ECB (39, 24), new
                        ECB (14, 25)), new ECBlocks (30, new ECB (22, 15), new ECB (41, 16))),
                new Version (36, new int[] { 6, 24, 50, 76, 102, 128, 154 },
                    new ECBlocks (30, new ECB (6, 121), new ECB (14, 122)),
                    new ECBlocks (28, new ECB (6, 47), new ECB (34, 48)),
                    new ECBlocks (30, new ECB (46, 24), new ECB (10, 25)),
                    new ECBlocks (30, new ECB (2, 15), new ECB (64, 16))),
                new Version (37, new int[] { 6, 28, 54, 80, 106, 132, 158 },
                    new ECBlocks (30, new ECB (17, 122), new ECB (4, 123)),
                    new ECBlocks (28, new ECB (29, 46), new ECB (14, 47)),
                    new ECBlocks (30, new ECB (49, 24), new ECB (10, 25)),
                    new ECBlocks (30, new ECB (24, 15), new ECB (46, 16))),
                new Version (38, new int[] { 6, 32, 58, 84, 110, 136, 162 },
                    new ECBlocks (30, new ECB (4, 122), new ECB (18, 123)),
                    new ECBlocks (28, new ECB (13, 46), new ECB (32, 47)),
                    new ECBlocks (30, new ECB (48, 24), new ECB (14, 25)),
                    new ECBlocks (30, new ECB (42, 15), new ECB (32, 16))),
                new Version (39, new int[] { 6, 26, 54, 82, 110, 138, 166 },
                    new ECBlocks (30, new ECB (20, 117), new ECB (4, 118)),
                    new ECBlocks (28, new ECB (40, 47), new ECB (7, 48)),
                    new ECBlocks (30, new ECB (43, 24), new ECB (22, 25)),
                    new ECBlocks (30, new ECB (10, 15), new ECB (67, 16))),
                new Version (40, new int[] { 6, 30, 58, 86, 114, 142, 170 },
                    new ECBlocks (30, new ECB (19, 118), new ECB (6, 119)),
                    new ECBlocks (28, new ECB (18, 47), new ECB (31, 48)),
                    new ECBlocks (30, new ECB (34, 24), new ECB (34, 25)),
                    new ECBlocks (30, new ECB (20, 15), new ECB (61, 16)))
            };
        }
    }
}
